//! 内存操作数编码工具
//! 
//! 提供 ModR/M 字节生成和内存寻址模式编码

use crate::ast::MemoryOperand;
use crate::error::{AssemblerError, Result};
use super::registers::RegisterEncoding;

/// 内存操作数编码工具
pub struct MemoryEncoder;

impl MemoryEncoder {
    /// 编码内存操作数为 ModR/M 字节和位移字节
    /// 
    /// 返回 (ModR/M 字节, 位移字节)
    pub fn encode_memory_operand(
        mem: &MemoryOperand,
        reg_field: u8,
    ) -> Result<(u8, Vec<u8>)> {
        // 8086 支持的内存寻址模式：
        // [bx + si] = 000
        // [bx + di] = 001
        // [bp + si] = 010
        // [bp + di] = 011
        // [si] = 100
        // [di] = 101
        // [bp] = 110 (但实际是 [bp + 0])
        // [bx] = 111

        let r_m = if let Some(base) = &mem.base {
            let base_code = RegisterEncoding::get_16bit_register_code(base)
                .ok_or_else(|| AssemblerError::OperandError {
                    message: format!("无效的基址寄存器: {}", base),
                    line: 0,
                })?;

            if let Some(index) = &mem.index {
                let index_code = RegisterEncoding::get_16bit_register_code(index)
                    .ok_or_else(|| AssemblerError::OperandError {
                        message: format!("无效的索引寄存器: {}", index),
                        line: 0,
                    })?;

                // 8086只支持特定的基址+索引组合
                match (base_code, index_code) {
                    (0b011, 0b110) => 0b000, // bx + si
                    (0b011, 0b111) => 0b001, // bx + di
                    (0b101, 0b110) => 0b010, // bp + si
                    (0b101, 0b111) => 0b011, // bp + di
                    _ => {
                        return Err(AssemblerError::OperandError {
                            message: "8086不支持此基址+索引组合".to_string(),
                            line: 0,
                        });
                    }
                }
            } else {
                // 只有基址寄存器
                match base_code {
                    0b110 => 0b110, // si
                    0b111 => 0b111, // di
                    0b101 => 0b110, // bp (作为 [bp])
                    0b011 => 0b111, // bx
                    _ => {
                        return Err(AssemblerError::OperandError {
                            message: format!("8086不支持此基址寄存器: {}", base),
                            line: 0,
                        });
                    }
                }
            }
        } else if let Some(index) = &mem.index {
            let index_code = RegisterEncoding::get_16bit_register_code(index)
                .ok_or_else(|| AssemblerError::OperandError {
                    message: format!("无效的索引寄存器: {}", index),
                    line: 0,
                })?;
            match index_code {
                0b110 => 0b100, // [si]
                0b111 => 0b101, // [di]
                _ => {
                    return Err(AssemblerError::OperandError {
                        message: "8086索引寄存器只能是源索引或目标索引".to_string(),
                        line: 0,
                    });
                }
            }
        } else {
            // 直接寻址 [disp]
            if mem.displacement.is_some() {
                0b110 // 使用bp编码，但mod=00表示无基址
            } else {
                return Err(AssemblerError::OperandError {
                    message: "内存操作数必须指定基址、索引或位移".to_string(),
                    line: 0,
                });
            }
        };

        // 计算mod和位移
        let (mod_field, disp_bytes) = if let Some(disp) = mem.displacement {
            if disp == 0 && r_m != 0b110 {
                // 无位移
                (0b00, Vec::new())
            } else if disp >= -128 && disp <= 127 {
                // 8位位移
                (0b01, vec![disp as u8])
            } else {
                // 16位位移
                let disp_u16 = disp as u16;
                (0b10, vec![disp_u16 as u8, (disp_u16 >> 8) as u8])
            }
        } else {
            (0b00, Vec::new())
        };

        let modrm = (mod_field << 6) | (reg_field << 3) | r_m;
        Ok((modrm, disp_bytes))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_encode_memory_bx() {
        let mem = MemoryOperand {
            base: Some("基址".to_string()),
            index: None,
            scale: None,
            displacement: None,
        };
        let (modrm, disp) = MemoryEncoder::encode_memory_operand(&mem, 0b000).unwrap();
        // [BX] = mod=00, r/m=111, reg=000 = 0b00000111 = 0x07
        assert_eq!(modrm, 0x07);
        assert_eq!(disp, vec![]);
    }

    #[test]
    fn test_encode_memory_bx_si() {
        let mem = MemoryOperand {
            base: Some("基址".to_string()),
            index: Some("源索引".to_string()),
            scale: None,
            displacement: None,
        };
        let (modrm, disp) = MemoryEncoder::encode_memory_operand(&mem, 0b000).unwrap();
        // [BX+SI] = mod=00, r/m=000, reg=000 = 0b00000000 = 0x00
        assert_eq!(modrm, 0x00);
        assert_eq!(disp, vec![]);
    }

    #[test]
    fn test_encode_memory_bx_disp8() {
        let mem = MemoryOperand {
            base: Some("基址".to_string()),
            index: None,
            scale: None,
            displacement: Some(10),
        };
        let (modrm, disp) = MemoryEncoder::encode_memory_operand(&mem, 0b000).unwrap();
        // [BX+10] = mod=01, r/m=111, reg=000 = 0b01000111 = 0x47
        assert_eq!(modrm, 0x47);
        assert_eq!(disp, vec![10]);
    }

    #[test]
    fn test_encode_memory_bx_disp16() {
        let mem = MemoryOperand {
            base: Some("基址".to_string()),
            index: None,
            scale: None,
            displacement: Some(1000),
        };
        let (modrm, disp) = MemoryEncoder::encode_memory_operand(&mem, 0b000).unwrap();
        // [BX+1000] = mod=10, r/m=111, reg=000 = 0b10000111 = 0x87
        assert_eq!(modrm, 0x87);
        let disp_u16 = 1000u16;
        assert_eq!(disp, vec![disp_u16 as u8, (disp_u16 >> 8) as u8]);
    }
}

